home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / gnu / gnpltsrc.lha / graph3d.c < prev    next >
C/C++ Source or Header  |  1996-01-22  |  55KB  |  1,914 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graph3d.c,v 1.85 1995/12/02 22:04:32 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graph3d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *
  20.  * This software is provided "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *       Gershon Elber and many others.
  27.  *
  28.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  29.  * Added user-specified bases for log scaling.
  30.  *
  31.  * 3.6 - split graph3d.c into graph3d.c (graph),
  32.  *                            util3d.c (intersections, etc)
  33.  *                            hidden3d.c (hidden-line removal code)
  34.  *
  35.  * There is a mailing list for gnuplot users. Note, however, that the
  36.  * newsgroup 
  37.  *    comp.graphics.gnuplot 
  38.  * is identical to the mailing list (they
  39.  * both carry the same set of messages). We prefer that you read the
  40.  * messages through that newsgroup, to subscribing to the mailing list.
  41.  * (If you can read that newsgroup, and are already on the mailing list,
  42.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  43.  * removed from the mailing list.)
  44.  *
  45.  * The address for mailing to list members is
  46.  *       info-gnuplot@dartmouth.edu
  47.  * and for mailing administrative requests is 
  48.  *       info-gnuplot-request@dartmouth.edu
  49.  * The mailing list for bug reports is 
  50.  *       bug-gnuplot@dartmouth.edu
  51.  * The list of those interested in beta-test versions is
  52.  *       info-gnuplot-beta@dartmouth.edu
  53.  */
  54.  
  55. #include <math.h>
  56. #if !defined(sequent) && !defined(apollo) && !defined(alliant)
  57. #include <limits.h>
  58. #endif
  59. #include "plot.h"
  60. #include "setshow.h"
  61.  
  62.  
  63. #define KEYWTH ( (int) (4*(t->h_char) + pointsize*(t->h_tic)))
  64.  
  65. extern TBOOLEAN term_graphics, term_suspended;
  66.  
  67. static int p_height;
  68. static int p_width;  /* pointsize * t->h_tic */
  69. static int key_entry_height;  /* bigger of t->v_size, pointsize*t->v_tick */
  70.  
  71. int suppressMove = 0;  /* for preventing moveto while drawing contours */
  72.  
  73. /*
  74.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  75.  *   for above and below parts of the surface.
  76.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  77.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  78.  *   do not influence the hidings.
  79.  * hidden_active - TRUE if hidden lines are to be removed.
  80.  */
  81. int hidden_active = FALSE;
  82.  
  83. /* LITE defines a restricted memory version for MS-DOS, which doesn't
  84.  * use the routines in hidden3d.c
  85.  */
  86.  
  87. #ifndef LITE
  88. int hidden_line_type_above, hidden_line_type_below;
  89. int hidden_no_update;
  90. #endif /* LITE */
  91.  
  92.  
  93. static double LogScale __P((double coord, TBOOLEAN is_log, double log_base_log,
  94.                             char *what,    char *axis));
  95. static void plot3d_impulses __P((struct surface_points *plot));
  96. static void plot3d_lines __P((struct surface_points *plot));
  97. static void plot3d_points __P((struct surface_points *plot));
  98. static void plot3d_dots __P((struct surface_points *plot));
  99. static void cntr3d_impulses __P((struct gnuplot_contours *cntr, struct surface_points *plot));
  100. static void cntr3d_lines __P((struct gnuplot_contours *cntr));
  101. static void cntr3d_points __P((struct gnuplot_contours *cntr, struct surface_points *plot));
  102. static void cntr3d_dots __P((struct gnuplot_contours *cntr));
  103. static void check_corner_height __P((struct coordinate GPHUGE *point, double height[2][2], double depth[2][2]));
  104. static void draw_bottom_grid __P((struct surface_points *plot, int plot_count));
  105. static void xtick_callback __P((int axis, double place, char *text, int grid));
  106. static void ytick_callback __P((int axis, double place, char *text, int grid));
  107. static void ztick_callback __P((int axis, double place, char *text, int grid));
  108. static void setlinestyle __P((int style));
  109.  
  110. static void boundary3d __P((int scaling, struct surface_points *plots, int count));
  111. #if 0 /* not used */
  112. static double dbl_raise __P((double x, int y));
  113. #endif
  114. static void map_position __P((struct position *pos, unsigned int *x, unsigned int *y, char *what));
  115.  
  116. /* put entries in the key */
  117. static void key_sample_line __P((int xl, int yl));
  118. static void key_sample_point __P((int xl, int yl, int pointtype));
  119. static void key_text __P((int xl, int yl, char *text));
  120.  
  121.  
  122. #if defined(sun386) || defined(AMIGA_SC_6_1)
  123. static double CheckLog __P((TBOOLEAN is_log, double base_log, double x));
  124. #endif
  125.  
  126.  
  127. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  128. #define max(a,b) ((a > b) ? a : b)
  129. #endif
  130.  
  131. #ifndef min
  132. #define min(a,b) ((a < b) ? a : b)
  133. #endif
  134.  
  135. /*
  136.  * The Amiga SAS/C 6.2 compiler moans about macro envocations causing
  137.  * multiple calls to functions. I converted these macros to inline
  138.  * functions coping with the problem without loosing speed.
  139.  * (MGR, 1993)
  140.  */
  141. #ifdef AMIGA_SC_6_1
  142. __inline static TBOOLEAN i_inrange(int z,int min,int max)
  143. {
  144.   return((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)));
  145. }
  146.  
  147. __inline static double f_max(double a,double b)
  148. {
  149.   return(max(a,b));
  150. }
  151.  
  152. __inline static double f_min(double a,double b)
  153. {
  154.   return(min(a,b));
  155. }
  156.  
  157. #else
  158. #define f_max(a,b) max((a),(b))
  159. #define f_min(a,b) min((a),(b))
  160. #define i_inrange(z,a,b) inrange((z),(a),(b))
  161. #endif
  162.  
  163. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  164.  
  165. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  166. #define ABS(x) ((x) >= 0 ? (x) : -(x))
  167. #define SQR(x) ((x) * (x))
  168.  
  169. /* Define the boundary of the plot
  170.  * These are computed at each call to do_plot, and are constant over
  171.  * the period of one do_plot. They actually only change when the term
  172.  * type changes and when the 'set size' factors change. 
  173.  */
  174.  
  175. /* in order to allow graphic.c to use clip_draw_line, we must
  176.  * share xleft, xright, ybot, ytop with graphics.c
  177.  */
  178. extern int xleft, xright, ybot, ytop;
  179.  
  180. int xmiddle, ymiddle, xscaler, yscaler;
  181. static int ptitl_cnt;
  182. static int max_ptitl_len;
  183. static int titlelin;
  184. static int key_rows, key_cols, key_col_wth, yl_ref;
  185. static int ktitle_lines = 0;
  186.  
  187.  
  188. /* Boundary and scale factors, in user coordinates */
  189. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  190.  * file and are not the same as variables of the same names in other files
  191.  */
  192. /*static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;*/
  193. /* sizes are now set in min_array[], max_array[] from command.c */
  194. extern double min_array[], max_array[];
  195. extern int auto_array[], log_array[];
  196. extern double base_array[], log_base_array[];
  197.  
  198. /* for convenience while converting to use these arrays */
  199. #define x_min3d min_array[FIRST_X_AXIS]
  200. #define x_max3d max_array[FIRST_X_AXIS]
  201. #define y_min3d min_array[FIRST_Y_AXIS]
  202. #define y_max3d max_array[FIRST_Y_AXIS]
  203. #define z_min3d min_array[FIRST_Z_AXIS]
  204. #define z_max3d max_array[FIRST_Z_AXIS]
  205.  
  206. /* There are several z's to take into account - I hope I get these
  207.  * right !
  208.  *
  209.  * ceiling_z is the highest z in use
  210.  * floor_z   is the lowest z in use
  211.  * base_z is the z of the base
  212.  * min3d_z is the lowest z of the graph area
  213.  * max3d_z is the highest z of the graph area
  214.  *
  215.  * ceiling_z is either max3d_z or base_z, and similarly for floor_z
  216.  * There should be no part of graph drawn outside
  217.  * min3d_z:max3d_z  - apart from arrows, perhaps
  218.  */
  219.  
  220. double ceiling_z, floor_z, base_z;
  221.  
  222. /* and some bodges while making the change */
  223. #define min3d_z min_array[FIRST_Z_AXIS]
  224. #define max3d_z max_array[FIRST_Z_AXIS]
  225.  
  226.  
  227. double xscale3d, yscale3d, zscale3d;
  228.  
  229.  
  230. typedef double transform_matrix[4][4];
  231. transform_matrix trans_mat;
  232.  
  233. static double xaxis_y, yaxis_x, zaxis_x, zaxis_y;
  234.  
  235. /* the co-ordinates of the back corner */
  236. static double back_x, back_y;
  237.  
  238. /* the penalty for convenience of using tic_gen to make callbacks
  239.  * to tick routines is that we cant pass parameters very easily.
  240.  * We communicate with the tick_callbacks using static variables
  241.  */
  242.  
  243. /* unit vector (terminal coords) */
  244. static double tic_unitx, tic_unity;
  245.  
  246. /* (DFK) Watch for cancellation error near zero on axes labels */
  247. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  248. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  249. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  250.  
  251. /* And the functions to map from user to terminal coordinates */
  252. #define map_x(x) (int)(x+0.5) /* maps floating point x to screen */ 
  253. #define map_y(y) (int)(y+0.5)    /* same for y */
  254.  
  255. /* And the functions to map from user 3D space into normalized -1..1 */
  256. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  257. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  258. #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
  259.  
  260.  
  261.  
  262. /* Initialize the line style using the current device and set hidden styles  */
  263. /* to it as well if hidden line removal is enabled.                 */
  264. static void setlinestyle(style)
  265. int style;
  266. {
  267.     register struct termentry *t = term;
  268.  
  269.     (*t->linetype)(style);
  270.  
  271. #ifndef LITE
  272.     if (hidden3d) {
  273.     hidden_line_type_above = style;
  274.     hidden_line_type_below = style;
  275.     }
  276. #endif  /* LITE */
  277. }
  278.  
  279. #ifndef LITE
  280. #endif /* not LITE */
  281.  
  282.  
  283.  
  284. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  285.  * macro, so I write it as a function on that machine.
  286.  *
  287.  * Amiga SAS/C 6.2 thinks it will do too much work calling functions in
  288.  * macro arguments twice, thus I inline theese functions. (MGR, 1993)
  289.  */
  290. #if defined(sun386) || defined(AMIGA_SC_6_1)
  291. #ifdef AMIGA_SC_6_1
  292. __inline
  293. #endif
  294. static double
  295. CheckLog(is_log, base_log, x)
  296.      TBOOLEAN is_log;
  297.      double base_log;
  298.      double x;
  299. {
  300.   if (is_log)
  301.     return(pow(base_log, x));
  302.   else
  303.     return(x);
  304. }
  305. #else
  306. /* (DFK) Use 10^x if logscale is in effect, else x */
  307. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  308. #endif /* sun386 || SAS/C */
  309.  
  310. static double
  311. LogScale(coord, is_log, log_base_log, what, axis)
  312.     double coord;            /* the value */
  313.     TBOOLEAN is_log;            /* is this axis in logscale? */
  314.     double log_base_log;        /* if so, the log of its base */
  315.     char *what;            /* what is the coord for? */
  316.     char *axis;            /* which axis is this for ("x" or "y")? */
  317. {
  318.     if (is_log) {
  319.        if (coord <= 0.0) {
  320.           char errbuf[100];        /* place to write error message */
  321.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  322.                 what, axis, coord);
  323.           graph_error(errbuf);
  324.        } else
  325.         return(log(coord)/log_base_log);
  326.     }
  327.     return(coord);
  328. }
  329.  
  330. /* And the functions to map from user 3D space to terminal coordinates */
  331. void map3d_xy(x, y, z, xt, yt)
  332. double x, y, z;
  333. unsigned int *xt, *yt;
  334. {
  335.     int i,j;
  336.     double v[4], res[4],             /* Homogeneous coords. vectors. */
  337.     w = trans_mat[3][3];
  338.  
  339.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  340.     v[1] = map_y3d(y);
  341.     v[2] = map_z3d(z);
  342.     v[3] = 1.0;
  343.  
  344.     for (i = 0; i < 2; i++) {                 /* Dont use the third axes (z). */
  345.         res[i] = trans_mat[3][i];     /* Initiate it with the weight factor. */
  346.         for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
  347.     }
  348.  
  349.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  350.     if (w == 0) w = 1e-5;
  351.  
  352.     *xt = (unsigned int) ((res[0] * xscaler / w) + xmiddle);
  353.     *yt = (unsigned int) ((res[1] * yscaler / w) + ymiddle);
  354. }
  355.  
  356.  
  357.  
  358. /* And the functions to map from user 3D space to terminal z coordinate */
  359. int map3d_z(x, y, z)
  360. double x, y, z;
  361. {
  362.     int i, zt;
  363.     double v[4], res,                 /* Homogeneous coords. vectors. */
  364.     w = trans_mat[3][3];
  365.  
  366.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  367.     v[1] = map_y3d(y);
  368.     v[2] = map_z3d(z);
  369.     v[3] = 1.0;
  370.  
  371.     res = trans_mat[3][2];               /* Initiate it with the weight factor. */
  372.     for (i = 0; i < 3; i++) res += v[i] * trans_mat[i][2];
  373.     if(w==0) w= 1e-5;
  374.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  375.     zt = ((int) (res * 16384 / w));
  376.     return  zt;
  377. }
  378.  
  379. /* borders of plotting area */
  380. /* computed once on every call to do_plot */
  381. static void boundary3d(scaling,plots,count)
  382.     TBOOLEAN scaling;    /* TRUE if terminal is doing the scaling */
  383.     struct surface_points *plots;
  384.     int count;
  385. {
  386.     register struct termentry *t = term;
  387.     int ytlen, i;
  388.  
  389.    titlelin = 0;
  390.  
  391.    p_height= pointsize * t->v_tic;
  392.    p_width = pointsize * t->h_tic;
  393.    key_entry_height = pointsize * (t->v_tic) * 1.25;
  394.    if (key_entry_height < (t->v_char) )
  395.     key_entry_height = (t->v_char);
  396.  
  397.    /* count max_len key and number keys (plot-titles and contour labels) with len > 0 */
  398.    max_ptitl_len = find_maxl_keys3d(plots,count,&ptitl_cnt);
  399.    if ( (ytlen = label_width(key_title,&ktitle_lines)) > max_ptitl_len )
  400.        max_ptitl_len = ytlen;
  401.    key_col_wth = (max_ptitl_len + 4 ) * (t->h_char) + KEYWTH;
  402.  
  403.     /* luecken@udel.edu modifications
  404.        sizes the plot to take up more of available resolution */
  405.    if ( lmargin >= 0 ) 
  406.        xleft = (t->h_char)*lmargin;
  407.    else
  408.        xleft = (t->h_char)*2 + (t->h_tic);
  409.    xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  410.    key_rows = ptitl_cnt;
  411.    key_cols = 1;
  412.    if (key == -1 && key_vpos == TUNDER ) {
  413.     /* calculate max no cols, limited by label-length */
  414.     key_cols = (int)(xright - xleft)/((max_ptitl_len + 4 ) * (t->h_char) + KEYWTH);
  415.     key_rows = (int)(ptitl_cnt/key_cols)+((ptitl_cnt%key_cols)>0);
  416.     /* now calculate actual no cols depending on no rows */
  417.     key_cols = (int)(ptitl_cnt/key_rows)+((ptitl_cnt%key_rows)>0); 
  418.     key_col_wth = (int)(xright - xleft)/key_cols;
  419.         /* key_rows += ktitle_lines; - messes up key - div */
  420.    }
  421.    /* this should also consider the view and number of lines in xformat || yformat || xlabel || ylabel */
  422.    ybot = (t->v_char)*2.5 + 1;  /* an absolute 1, with no terminal-dependent scaling ? */
  423.    if (key_rows&&key_vpos==TUNDER)
  424.       ybot += key_rows*key_entry_height + ktitle_lines*t->v_char;
  425.  
  426.    if (strlen(title.text)) {
  427.     titlelin++;
  428.      for(i=0;i<strlen(title.text);i++) {
  429.          if (title.text[i] == '\\') titlelin++;
  430.      }
  431.    }
  432.    ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*(titlelin+1.5) - 1;
  433.    if (key == -1 && key_vpos != TUNDER ) {
  434.     /* calculate max no rows, limited be ytop-ybot */
  435.     i = (int)(ytop-ybot)/(t->v_char) - 1 - ktitle_lines;
  436.     if (ptitl_cnt > i) {
  437.         key_cols = (int)(ptitl_cnt/i)+((ptitl_cnt%i)>0);
  438.         /* now calculate actual no rows depending on no cols */
  439.         key_rows = (int)(ptitl_cnt/key_cols)+((ptitl_cnt%key_cols)>0);
  440.     }
  441.     key_rows += ktitle_lines;
  442.    }
  443.    if ( key_hpos == TOUT ) {
  444.     xright -= key_col_wth*(key_cols-1) + key_col_wth - 2*(t->h_char); 
  445.    }
  446.  
  447.    xleft  += t->xmax * xoffset;
  448.    xright += t->xmax * xoffset;
  449.    ytop   += t->ymax * yoffset;
  450.    ybot   += t->ymax * yoffset;
  451.    xmiddle = (xright + xleft) / 2;
  452.    ymiddle = (ytop + ybot) / 2;
  453.    xscaler = (xright - xleft) * 4 / 7;
  454.    yscaler = (ytop - ybot) * 4 / 7;
  455. }
  456.  
  457. #if 0
  458. /* not used ; anyway, should be done using bitshifts and squares,
  459.  * rather than iteratively
  460.  */
  461. static double dbl_raise(x,y)
  462. double x;
  463. int y;
  464. {
  465. register int i=ABS(y);
  466. double val=1.0;
  467.     while (--i >= 0)
  468.         val *= x;
  469.     if (y < 0 ) return (1.0/val);
  470.     return(val);
  471. }
  472. #endif
  473.  
  474. /* we precalculate features of the key, to save lots of nested
  475.  * ifs in code - x,y = user supplied or computed position of key
  476.  * taken to be inner edge of a line sample
  477.  */
  478. static int key_sample_left;   /* offset from x for left of line sample */
  479. static int key_sample_right;  /* offset from x for right of line sample */
  480. static int key_point_offset;  /* offset from x for point sample */
  481. static int key_text_left;     /* offset from x for left-justified text */
  482. static int key_text_right;    /* offset from x for right-justified text */
  483. static int key_size_left;     /* distance from x to left edge of box */
  484. static int key_size_right;    /* distance from x to right edge of box */
  485.  
  486.  
  487.  
  488. void do_3dplot(plots, pcount)
  489. struct surface_points *plots;
  490. int pcount;            /* count of plots in linked list */
  491. {
  492. struct termentry *t = term;
  493. int surface;
  494. struct surface_points *this_plot = NULL;
  495. unsigned int xl, yl;
  496. int linetypeOffset = 0;
  497. double ztemp, temp;
  498. struct text_label *this_label;
  499. struct arrow_def *this_arrow;
  500. TBOOLEAN scaling;
  501. transform_matrix mat;
  502. int key_count;
  503. char ss[MAX_LINE_LEN+1], *s, *e;
  504.  
  505. /* Initiate transformation matrix using the global view variables. */
  506.     mat_rot_z(surface_rot_z, trans_mat);
  507.     mat_rot_x(surface_rot_x, mat);
  508.     mat_mult(trans_mat, trans_mat, mat);
  509.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  510.     mat_mult(trans_mat, trans_mat, mat);
  511.  
  512. /* modify min_z/max_z so it will zscale properly. */
  513.     ztemp = (z_max3d - z_min3d) / (2.0 * surface_zscale);
  514.     temp = (z_max3d + z_min3d) / 2.0;
  515.     z_min3d = temp - ztemp;
  516.     z_max3d = temp + ztemp;
  517.  
  518. #if 0 /* already done in eval_3dplots */
  519.     /* auto-extend ranges to tic-mark for autoscaled axes */
  520.     if (xtics) setup_tics(FIRST_X_AXIS, &xticdef, xformat);
  521.     if (ytics) setup_tics(FIRST_Y_AXIS, &yticdef, yformat);
  522.     if (ztics) setup_tics(FIRST_Z_AXIS, &zticdef, zformat);
  523. #endif
  524.  
  525.     /* The extrema need to be set even when a surface is not being
  526.      * drawn.   Without this, gnuplot used to assume that the X and
  527.      * Y axis started at zero.   -RKC
  528.      */
  529.  
  530.     if (polar)
  531.     graph_error("Cannot splot in polar coordinate system.");
  532.  
  533. /* done in plot3d.c
  534.  *    if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  535.  *    x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  536.  *    y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  537.  *      graph_error("all points undefined!");
  538.  */
  539.  
  540.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  541.     if (xtics || ytics || grid) {
  542.     base_z = z_min3d - (z_max3d - z_min3d) * ticslevel;
  543.     if (ticslevel >= 0)
  544.         floor_z = base_z;
  545.     else
  546.         floor_z = z_min3d;
  547.  
  548.     if (ticslevel < -1)
  549.         ceiling_z = base_z;
  550.     else
  551.         ceiling_z = z_max3d;
  552.     } else {
  553.     floor_z = base_z = z_min3d;
  554.     ceiling_z = z_max3d;
  555.     }
  556.  
  557. /*  This used be x_max3d == x_min3d, but that caused an infinite loop once. */
  558.     if (fabs(x_max3d - x_min3d) < zero)
  559.     graph_error("x_min3d should not equal x_max3d!");
  560.     if (fabs(y_max3d - y_min3d) < zero)
  561.     graph_error("y_min3d should not equal y_max3d!");
  562.     if (fabs(z_max3d - z_min3d) < zero)
  563.     graph_error("z_min3d should not equal z_max3d!");
  564.  
  565. #ifndef LITE
  566.     if (hidden3d) {
  567.     struct surface_points *plot;
  568.     int p=0;
  569.         /* Verify data is hidden line removable - grid based. */
  570.           for (plot = plots; ++p <= pcount; plot = plot->next_sp) {
  571.          if (plot->plot_type == DATA3D && !plot->has_grid_topology){
  572.           fprintf(stderr,"Notice: Cannot remove hidden lines from non grid data\n");
  573.               return;
  574.             }
  575.     
  576.         }
  577.     }
  578. #endif /* not LITE */
  579.  
  580. /* INITIALIZE TERMINAL */
  581.     if (!term_init) {
  582.     (*t->init)();
  583.     term_init = TRUE;
  584.     }
  585.     screen_ok = FALSE;
  586.     scaling = (*t->scale)(xsize, ysize);
  587.  
  588.     if (multiplot && term_graphics) {
  589.         if (term_suspended && term->resume)
  590.             (*t->resume)();
  591.         term_suspended = FALSE;
  592.      } else {
  593.         (*t->graphics)();
  594.         term_graphics = TRUE;
  595.      }
  596.  
  597.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  598.     boundary3d(scaling,plots,pcount);
  599.  
  600. /* SCALE FACTORS */
  601.     zscale3d = 2.0/(ceiling_z - floor_z);
  602.     yscale3d = 2.0/(y_max3d - y_min3d);
  603.     xscale3d = 2.0/(x_max3d - x_min3d);
  604.  
  605.     (*t->linetype)(-2); /* border linetype */
  606.  
  607. /* PLACE TITLE */
  608.     if (*title.text != 0) {
  609.         strcpy(ss, title.text);
  610.         write_multiline( (unsigned int)((xleft+xright)/2+title.xoffset*t->h_char),
  611.                          (unsigned int)(ytop+(titlelin+title.yoffset)*(t->h_char)),
  612.                          ss, CENTRE, JUST_TOP, 0, title.font);
  613.     }
  614.  
  615. /* PLACE TIMEDATE */
  616.     if (*timelabel.text) {
  617.         char str[MAX_LINE_LEN+1];
  618.         time_t now;
  619.         unsigned int x = t->v_char + timelabel.xoffset * t->h_char;
  620.         unsigned int y = yoffset*ymax + (timelabel.yoffset+1) * t->v_char;
  621.  
  622.         time(&now);
  623.         strftime(str, MAX_LINE_LEN, timelabel.text, localtime(&now));
  624.  
  625.         if ((*t->text_angle)(1)) {
  626.             write_multiline(x,y,str,CENTRE, JUST_TOP, 1, timelabel.font);
  627.             (*t->text_angle)(0);
  628.         } else {
  629.             write_multiline(x,y,str,LEFT, JUST_BOT, 0, timelabel.font);
  630.         }
  631.     }
  632.  
  633. /* PLACE LABELS */
  634.     for (this_label = first_label; this_label!=NULL;
  635.             this_label=this_label->next ) {
  636.     unsigned int x,y;
  637.  
  638.     map_position(&this_label->place, &x, &y, "label");
  639.     strcpy(ss, this_label->text);
  640.     write_multiline( x,y, this_label->text, this_label->pos, CENTRE, 0, this_label->font);
  641.     }
  642.  
  643. /* PLACE ARROWS */
  644.     for (this_arrow = first_arrow; this_arrow!=NULL;
  645.         this_arrow = this_arrow->next ) {
  646.     unsigned int sx,sy,ex,ey;
  647.     map_position(&this_arrow->start, &sx, &sy, "arrow");
  648.     map_position(&this_arrow->end, &ex, &ey, "arrow");
  649.     (*t->linetype)(this_arrow->line);
  650.     (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  651.     }
  652.  
  653. #ifndef LITE
  654.     if (hidden3d && draw_surface) {
  655.     init_hidden_line_removal();
  656.     reset_hidden_line_removal();
  657.     hidden_active = TRUE;
  658.     }
  659. #endif /* not LITE */
  660.  
  661. /* WORK OUT KEY SETTINGS AND DO KEY TITLE / BOX */
  662.  
  663.     if (key_reverse) {
  664.         key_sample_left= -KEYWTH;
  665.         key_sample_right= 0;
  666.         key_text_left=t->h_char;
  667.         key_text_right=(t->h_char)*(max_ptitl_len+1);
  668.         key_size_right=(t->h_char)*(max_ptitl_len+2);
  669.         key_size_left=(t->h_char) + KEYWTH;
  670.     } else {
  671.         key_sample_left= 0;
  672.         key_sample_right= KEYWTH;
  673.         key_text_left=-(t->h_char)*(max_ptitl_len+1);
  674.         key_text_right=-(t->h_char);
  675.         key_size_left=(t->h_char)*(max_ptitl_len+2);
  676.         key_size_right=(t->h_char)+KEYWTH;
  677.     }
  678.     key_point_offset = (key_sample_left + key_sample_right)/2;
  679.  
  680.     if (key == -1) {
  681.          if ( key_vpos == TUNDER ) {
  682. #if 0
  683.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines+2)*t->v_char;
  684.         xl = max_ptitl_len * 1000/( KEYWTH/(t->h_char) + max_ptitl_len + 2);
  685.         xl *= (xright - xleft)/key_cols;
  686.         xl /= 1000;
  687.         xl += xleft;
  688. #else
  689.         /* maximise no cols, limited by label-length */
  690.         key_cols = (int)(xright - xleft)/key_col_wth;
  691.         key_rows = (int)(ptitl_cnt+key_cols-1)/key_cols;
  692.         /* now calculate actual no cols depending on no rows */
  693.         key_cols = (int)(ptitl_cnt+key_rows-1)/key_rows; 
  694.         key_col_wth = (int)(xright - xleft)/key_cols;
  695.         /* we divide into columns, then centre in column by considering ratio
  696.          * of key_left_size to key_right_size
  697.          * key_size_left/(key_size_left+key_size_right) * (xright-xleft)/key_cols
  698.          * do one integer division to maximise accuracy (hope we dont overflow !)
  699.          */
  700.         xl = xleft + ((xright-xleft)*key_size_left) / (key_cols*(key_size_left+key_size_right));
  701.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines+2)*t->v_char;
  702. #endif
  703.         } else {
  704.              if ( key_vpos == TTOP ) {
  705.                  yl = ytop - (t->v_tic) - t->v_char;
  706.              } else {
  707.                  yl = ybot + (t->v_tic) + key_entry_height*key_rows + ktitle_lines*t->v_char;
  708.              }
  709.              if ( key_hpos == TOUT ) {
  710.             /* keys outside plot border (right) */
  711.                  xl = xright  + (t->h_tic) + key_size_left;
  712.              } else if ( key_hpos == TLEFT ) {
  713.                  xl = xleft  + (t->h_tic) + key_size_left;
  714.              } else { 
  715.                  xl = xright  - key_size_right - key_col_wth*(key_cols-1); 
  716.             }
  717.        }
  718.        yl_ref = yl - ktitle_lines * (t->v_char);
  719.      }
  720.       if (key == 1) {
  721.           map_position(&key_user_pos, &xl, &yl, "key");
  722.     }
  723.  
  724.     if (key && key_box>-3) {
  725.         int yt=yl;
  726.         int yb=yl - key_entry_height*(key_rows-ktitle_lines) - ktitle_lines*t->v_char;
  727.        int key_xr = xl + key_col_wth * (key_cols-1) + key_size_right;
  728.         /* key_rows seems to contain title at this point ??? */
  729.         (*t->linetype)(key_box);
  730.         (*t->move)(xl-key_size_left,yb);
  731.         (*t->vector)(xl-key_size_left,yt);
  732.         (*t->vector)(key_xr,yt);
  733.         (*t->vector)(key_xr,yb);
  734.         (*t->vector)(xl-key_size_left,yb);
  735.                 /* draw a horizontal line between key title and first entry */   /* JFi */
  736.         (*t->move)(xl-key_size_left,yt - (ktitle_lines) * t->v_char);    /* JFi */
  737.                 (*t->vector)(xl+key_size_right,yt - (ktitle_lines) * t->v_char); /* JFi */
  738.     }
  739.  
  740. /* DRAW SURFACES AND CONTOURS */
  741.  
  742. #ifndef LITE
  743.     if (hidden3d && draw_surface) plot3d_hidden(plots,pcount);
  744. #endif /* not LITE */
  745.     if (key != 0 && strlen(key_title)) {
  746.         sprintf(ss,"%s\n",key_title);
  747.         s = ss;
  748.         yl -= t->v_char/2;
  749.         while( (e=(char *)strchr(s,'\n')) != NULL ) {
  750.             *e = '\0';
  751.             if ( key_just == JLEFT) {
  752.                 (*t->justify_text)(LEFT);
  753.                 (*t->put_text)(xl+key_text_left,yl,s);
  754.             } else {
  755.                 if ((*t->justify_text)(RIGHT)) {
  756.                     (*t->put_text)(xl+key_text_right,
  757.                         yl,s);
  758.                 } else {
  759.                     int x=xl+key_text_right-(t->h_char)*strlen(s);
  760.                     if (inrange(x,xleft, xright))
  761.                         (*t->put_text)(x,yl,s);
  762.                 }
  763.             }
  764.             s = ++e;
  765.             yl -= t->v_char;
  766.         }
  767.         yl += t->v_char/2;
  768.     }
  769.     key_count = 0;
  770.     yl_ref = yl -= key_entry_height/2;  /* centralise the keys */
  771.  
  772.     this_plot = plots;
  773.     for (surface = 0;
  774.          surface < pcount;
  775.          this_plot = this_plot->next_sp, surface++) {
  776. #ifndef LITE
  777.         if ( hidden3d )
  778.             hidden_no_update = FALSE;
  779. #endif /* not LITE */
  780.  
  781.         if (draw_surface) {
  782.             (*t->linetype)(this_plot->line_type);
  783. #ifndef LITE
  784.             if (hidden3d) {
  785.             hidden_line_type_above = this_plot->line_type;
  786.             hidden_line_type_below = this_plot->line_type + 1;
  787.             }
  788. #endif /* not LITE */            
  789.             if (key != 0 && this_plot->title) {
  790.             key_count++;
  791.             key_text(xl, yl, this_plot->title);
  792.             }
  793.             
  794.             switch(this_plot->plot_style) {
  795.                 case BOXES: /* can't do boxes in 3d yet so use impulses */
  796.                 case IMPULSES: {
  797.                 if (key != 0 && this_plot->title) {
  798.                     key_sample_line(xl,yl);
  799.                 }
  800.                 if (!(hidden3d && draw_surface))
  801.                   plot3d_impulses(this_plot);
  802.                 break;
  803.             }
  804.             case LINES: {
  805.                 if (key != 0 && this_plot->title) {
  806.                     key_sample_line(xl,yl);
  807.                  }
  808.                 if (!(hidden3d && draw_surface))
  809.                   plot3d_lines(this_plot);
  810.                 break;
  811.             }
  812.                         case YERRORBARS: /* ignored; treat like points */
  813.                         case XERRORBARS: /* ignored; treat like points */
  814.                         case XYERRORBARS: /* ignored; treat like points */
  815.             case POINTSTYLE: {
  816.                 if (key != 0 && this_plot->title 
  817.                 && !clip_point(xl+key_point_offset,yl)) {
  818.                     key_sample_point(xl,yl,this_plot->point_type);
  819.                 }
  820.                 if (!(hidden3d && draw_surface))
  821.                   plot3d_points(this_plot);
  822.                 break;
  823.             }
  824.             case LINESPOINTS: {
  825.                 /* put lines */
  826.                 if (key != 0 && this_plot->title) {
  827.                     key_sample_line(xl,yl);
  828.                 }
  829.                  if (!(hidden3d && draw_surface))
  830.                    plot3d_lines(this_plot);
  831.             
  832.                 /* put points */
  833.                 if (key != 0 && this_plot->title 
  834.                 && !clip_point(xl+key_point_offset,yl)) {
  835.                 (*t->point)(xl+key_point_offset,yl,
  836.                         this_plot->point_type);
  837.                 }
  838.                 if (!(hidden3d && draw_surface))
  839.                   plot3d_points(this_plot);
  840.                 break;
  841.             }
  842.             case DOTS: {
  843.                 if (key != 0 && this_plot->title) {
  844.                     if (key == 1) {
  845.                      if (!clip_point(xl+key_point_offset,yl)) 
  846.                         (*t->point)(xl+key_point_offset,yl, -1);
  847.                     } else {
  848.                     (*t->point)(xl+key_point_offset,yl, -1);
  849.                 /* (*t->point)(xl+2*(t->h_char),yl, -1); */
  850.                     }
  851.                 }
  852.                 if (!(hidden3d && draw_surface))
  853.                   plot3d_dots(this_plot);
  854.                 break;
  855.             }
  856.             }
  857.             if (key != 0 && this_plot->title) {
  858.                 if ( key_count >= key_rows ) {
  859.                 yl = yl_ref;
  860.                 xl += key_col_wth;
  861.                 key_count = 0;
  862.                 } else 
  863.                     yl -= key_entry_height;
  864.             }
  865.         }
  866.  
  867. #ifndef LITE
  868.         if ( hidden3d ) {
  869.             hidden_no_update = TRUE;
  870.             hidden_line_type_above = this_plot->line_type + (hidden3d ? 2 : 1);
  871.             hidden_line_type_below = this_plot->line_type + (hidden3d ? 2 : 1);
  872.         }
  873. #endif /* not LITE */
  874.  
  875.         if (draw_contour && this_plot->contours != NULL) {
  876.             struct gnuplot_contours *cntrs = this_plot->contours;
  877.  
  878.             (*t->linetype)(this_plot->line_type + (hidden3d ? 2 : 1));
  879.             if (key != 0 && this_plot->title 
  880.                       && !draw_surface && !label_contours) {
  881.                 key_count++;
  882.                 key_text(xl,yl, this_plot->title);
  883.                 
  884.                 switch(this_plot->plot_style) {
  885.                     case IMPULSES:
  886.                     case LINES:
  887.                         key_sample_line(xl,yl);
  888.                         break;
  889.                                         case YERRORBARS: /* ignored; treat like points */
  890.                                         case XERRORBARS: /* ignored; treat like points */
  891.                                         case XYERRORBARS: /* ignored; treat like points */
  892.                     case POINTSTYLE:
  893.                         key_sample_point(xl,yl,this_plot->point_type);
  894.                         break;
  895.                       case LINESPOINTS:
  896.                         key_sample_line(xl,yl);
  897.                         break;
  898.                     case DOTS:
  899.                         key_sample_point(xl,yl,-1);
  900.                         break;
  901.                 }
  902.             }
  903.  
  904.             linetypeOffset = this_plot->line_type + (hidden3d ? 2 : 1);
  905.             while (cntrs) {
  906.                 if(label_contours && cntrs->isNewLevel) {
  907.                   (*t->linetype)(linetypeOffset++);
  908.                   if (key) {
  909. #ifndef LITE
  910.                     if(hidden3d) hidden_line_type_below = hidden_line_type_above = linetypeOffset-1;
  911. #endif /* not LITE */
  912.                     key_count++;
  913.                     key_text(xl,yl,cntrs->label);
  914.                     
  915.                         switch(this_plot->plot_style) {
  916.                         case IMPULSES:
  917.                         case LINES:
  918.                         case LINESPOINTS:
  919.                         key_sample_line(xl,yl);
  920.                          break;
  921.                                            case YERRORBARS: /* ignored; treat like points */
  922.                                            case XERRORBARS: /* ignored; treat like points */
  923.                                            case XYERRORBARS: /* ignored; treat like points */
  924.                         case POINTSTYLE:
  925.                             key_sample_point(xl,yl,this_plot->point_type);
  926.                             break;
  927.                        case DOTS:
  928.                            key_sample_point(xl,yl,-1);
  929.                            break;
  930.                        } /* switch */
  931.                        
  932.                           if (key_count >= key_rows ) {
  933.                             yl = yl_ref;
  934.                             xl += key_col_wth;
  935.                             key_count = 0;
  936.                         } else  /* might want to use t->v_char if not putting points in key - div */
  937.                             yl -= key_entry_height;
  938.  
  939.                    } /* key */
  940.                 } /* label_contours */
  941.                 switch(this_plot->plot_style) {
  942.                     case IMPULSES:
  943.                            cntr3d_impulses(cntrs, this_plot);
  944.                         break;
  945.                     case LINES:
  946.                         cntr3d_lines(cntrs);
  947.                         break;
  948.                                         case YERRORBARS: /* ignored; treat like points */
  949.                                         case XERRORBARS: /* ignored; treat like points */
  950.                                         case XYERRORBARS: /* ignored; treat like points */
  951.                     case POINTSTYLE:
  952.                         cntr3d_points(cntrs, this_plot);
  953.                         break;
  954.                     case LINESPOINTS:
  955.                         cntr3d_lines(cntrs);
  956.                         cntr3d_points(cntrs, this_plot);
  957.                         break;
  958.                     case DOTS:
  959.                         cntr3d_dots(cntrs);
  960.                         break;
  961.                 }
  962.                 cntrs = cntrs->next;
  963.             }
  964.             if (key != 0 && this_plot->title) {
  965.                     if (key_count >= key_rows ) {
  966.                 yl = yl_ref;
  967.                 xl += key_col_wth;
  968.                 key_count = 0;
  969.                     } else 
  970.                     yl -= key_entry_height;
  971.             }
  972.           }
  973.       }
  974.  
  975.     draw_bottom_grid(plots, pcount);
  976.  
  977.     if (!multiplot) {
  978.         (*t->text)();
  979.         term_graphics = FALSE;
  980.     }
  981.     
  982.     (void) fflush(outfile);
  983.  
  984. #ifndef LITE
  985.     if (hidden3d && draw_surface) {
  986.         term_hidden_line_removal();
  987.         hidden_active = FALSE;
  988.     }
  989. #endif /* not LITE */
  990. }
  991.  
  992. /* plot3d_impulses:
  993.  * Plot the surfaces in IMPULSES style
  994.  */
  995. static void plot3d_impulses(plot)
  996.     struct surface_points *plot;
  997. {
  998.     int i;                /* point index */
  999.     unsigned int x,y,x0,y0;            /* point in terminal coordinates */
  1000.     struct iso_curve *icrvs = plot->iso_crvs;
  1001.  
  1002.     while ( icrvs ) {
  1003.     struct coordinate GPHUGE *points = icrvs->points;
  1004.  
  1005.     for (i = 0; i < icrvs->p_count; i++) {
  1006.       switch (points[i].type)
  1007.         {
  1008.         case INRANGE:
  1009.           {
  1010.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1011.  
  1012.         if(inrange(0.0, min3d_z, max3d_z)){
  1013.           map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1014.         } else if(inrange(min3d_z, 0.0, points[i].z)){
  1015.           map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1016.         } else {
  1017.           map3d_xy(points[i].x, points[i].y, max3d_z, &x0, &y0);
  1018.         }
  1019.         
  1020.         clip_move(x0,y0);
  1021.         clip_vector(x,y);
  1022.         
  1023.         break;
  1024.           }
  1025.         case OUTRANGE:
  1026.           {
  1027.         if(!inrange(points[i].x, x_min3d, x_max3d) ||
  1028.            !inrange(points[i].y, y_min3d, y_max3d))
  1029.           break;        
  1030.         
  1031.         if(inrange(0.0, min3d_z, max3d_z))
  1032.           {
  1033.             /* zero point is INRANGE */
  1034.             map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1035.  
  1036.             /* must cross z=min3d_z or max3d_z limits */
  1037.             if(inrange(min3d_z, 0.0, points[i].z) && 
  1038.                min3d_z != 0.0 && min3d_z != points[i].z)
  1039.               {
  1040.             map3d_xy(points[i].x, points[i].y, min3d_z, &x, &y);
  1041.               } 
  1042.             else
  1043.               {
  1044.             map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1045.               }
  1046.           } 
  1047.         else 
  1048.           { 
  1049.             /* zero point is also OUTRANGE */ 
  1050.             if(inrange(min3d_z, 0.0, points[i].z) && 
  1051.                inrange(max3d_z, 0.0, points[i].z))
  1052.               {
  1053.             /* crosses z=min3d_z or max3d_z limits */
  1054.             map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1055.             map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1056.               }
  1057.             else 
  1058.               {
  1059.             /* doesn't cross z=min3d_z or max3d_z limits */
  1060.             break;
  1061.               }
  1062.           }
  1063.  
  1064.         clip_move(x0,y0);
  1065.         clip_vector(x,y);
  1066.         
  1067.         break;
  1068.           }          
  1069.         default:        /* just a safety */
  1070.         case UNDEFINED: {
  1071.           break;
  1072.         }
  1073.         }
  1074.         }
  1075.  
  1076.     icrvs = icrvs->next;
  1077.       }
  1078. }
  1079.  
  1080. /* plot3d_lines:
  1081.  * Plot the surfaces in LINES style
  1082.  */
  1083. /* We want to always draw the lines in the same direction, otherwise when
  1084.    we draw an adjacent box we might get the line drawn a little differently
  1085.    and we get splotches.  */
  1086.  
  1087. #ifndef LITE
  1088. #endif /* not LITE */
  1089.  
  1090. static void plot3d_lines(plot)
  1091.     struct surface_points *plot;
  1092. {
  1093.     int i;
  1094.     unsigned int x,y,x0,y0;                /* point in terminal coordinates */
  1095.      double clip_x, clip_y, clip_z;
  1096.     struct iso_curve *icrvs = plot->iso_crvs;
  1097.     struct coordinate GPHUGE *points;
  1098.      enum coord_type prev = UNDEFINED;
  1099.      double lx[2], ly[2], lz[2];        /* two edge points */
  1100.  
  1101. #ifndef LITE
  1102. /* These are handled elsewhere.  */
  1103.     if (plot->has_grid_topology && hidden3d)
  1104.     return;
  1105. #endif /* not LITE */
  1106.  
  1107.     while (icrvs) {
  1108.       prev = UNDEFINED; /* type of previous plot */
  1109.  
  1110.     for(i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1111.        switch (points[i].type) {
  1112.           case INRANGE: {
  1113.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1114.             
  1115.             if(prev == INRANGE)
  1116.               {
  1117.             clip_vector(x, y);
  1118.               }
  1119.             else
  1120.               {
  1121.             if(prev == OUTRANGE)              
  1122.               {
  1123.                 /* from outrange to inrange */
  1124.                 if (!clip_lines1) {
  1125.                   clip_move(x, y);
  1126.                 }
  1127.                 else {
  1128.                   /*
  1129.                    * Calculate intersection point and draw vector from there
  1130.                    */
  1131.                   edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1132.                   
  1133.                   map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1134.                   
  1135.                   clip_move(x0,y0);
  1136.                   clip_vector(x,y);
  1137.                 }
  1138.               }
  1139.             else
  1140.               {
  1141.                 clip_move(x,y);
  1142.               }
  1143.               }
  1144.  
  1145.             break;
  1146.           }
  1147.           case OUTRANGE:{
  1148.             if(prev == INRANGE)
  1149.               {
  1150.             /* from inrange to outrange */
  1151.             if (clip_lines1) {
  1152.               /*
  1153.                * Calculate intersection point and draw vector to it
  1154.                */
  1155.               
  1156.               edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1157.               
  1158.               map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1159.               
  1160.               clip_vector(x0,y0);
  1161.             }
  1162.               }
  1163.             else if (prev == OUTRANGE)
  1164.               {
  1165.             /* from outrange to outrange */
  1166.             if (clip_lines2) {
  1167.               /*
  1168.                * Calculate the two 3D intersection points if present
  1169.                */
  1170.               if (two_edge3d_intersect(points, i, lx, ly, lz)) {
  1171.  
  1172.                 map3d_xy(lx[0], ly[0], lz[0], &x, &y);
  1173.  
  1174.                 map3d_xy(lx[1], ly[1], lz[1], &x0, &y0);
  1175.  
  1176.                 clip_move(x, y);
  1177.                 clip_vector(x0, y0);
  1178.               }
  1179.             }
  1180.               }
  1181.  
  1182.             break;
  1183.           }
  1184.           case UNDEFINED: {
  1185.             break;
  1186.           default: graph_error("Unknown point type in plot3d_lines");
  1187.           }
  1188.            }
  1189.  
  1190.        prev = points[i].type;
  1191.      }
  1192.  
  1193.     icrvs = icrvs->next;
  1194.     }
  1195. }
  1196.  
  1197. /* plot3d_points:
  1198.  * Plot the surfaces in POINTSTYLE style
  1199.  */
  1200. static void plot3d_points(plot)
  1201.     struct surface_points *plot;
  1202. {
  1203.     int i;
  1204.     unsigned x,y;
  1205.     struct termentry *t = term;
  1206.     struct iso_curve *icrvs = plot->iso_crvs;
  1207.  
  1208.     while ( icrvs ) {
  1209.     struct coordinate GPHUGE *points = icrvs->points;
  1210.  
  1211.     for (i = 0; i < icrvs->p_count; i++) {
  1212.       if (points[i].type == INRANGE) {
  1213.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1214.  
  1215.         if (!clip_point(x,y))
  1216.         (*t->point)(x,y, plot->point_type);
  1217.       }
  1218.     }
  1219.  
  1220.     icrvs = icrvs->next;
  1221.     }
  1222. }
  1223.  
  1224. /* plot3d_dots:
  1225.  * Plot the surfaces in DOTS style
  1226.  */
  1227. static void plot3d_dots(plot)
  1228.     struct surface_points *plot;
  1229. {
  1230.     int i;
  1231.     struct termentry *t = term;
  1232.     struct iso_curve *icrvs = plot->iso_crvs;
  1233.  
  1234.     while ( icrvs ) {
  1235.     struct coordinate GPHUGE *points = icrvs->points;
  1236.  
  1237.         for (i = 0; i < icrvs->p_count; i++) {
  1238.             unsigned int x,y;
  1239.            map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1240.  
  1241.             if (!clip_point(x,y))
  1242.         (*t->point)(x,y, -1);
  1243.         }
  1244.  
  1245.     icrvs = icrvs->next;
  1246.     }
  1247. }
  1248.  
  1249. /* cntr3d_impulses:
  1250.  * Plot a surface contour in IMPULSES style
  1251.  */
  1252. static void cntr3d_impulses(cntr, plot)
  1253.     struct gnuplot_contours *cntr;
  1254.     struct surface_points *plot;
  1255. {
  1256.     int i;                /* point index */
  1257.     unsigned int x,y,x0,y0;            /* point in terminal coordinates */
  1258.  
  1259.     if (draw_contour & CONTOUR_SRF) {
  1260.     for (i = 0; i < cntr->num_pts; i++) {
  1261.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1262.              &x, &y);
  1263.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1264.              &x0, &y0);
  1265.  
  1266.         clip_move(x0,y0);
  1267.         clip_vector(x,y);
  1268.     }
  1269.     }
  1270.     else
  1271.     cntr3d_points(cntr, plot);   /* Must be on base grid, so do points. */
  1272. }
  1273.  
  1274. /* cntr3d_lines:
  1275.  * Plot a surface contour in LINES style
  1276.  */
  1277. static void cntr3d_lines(cntr)
  1278.     struct gnuplot_contours *cntr;
  1279. {
  1280.     int i;                /* point index */
  1281.     unsigned int x,y;                /* point in terminal coordinates */
  1282.  
  1283.     if (draw_contour & CONTOUR_SRF) {
  1284.     for (i = 0; i < cntr->num_pts; i++) {
  1285.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1286.                  &x, &y);
  1287.  
  1288.              if (i > 0) {
  1289.                  clip_vector(x,y);
  1290.                  if(i == 1) suppressMove = TRUE;
  1291.              } else {
  1292.                  clip_move(x,y);
  1293.              }
  1294.         }
  1295.     }
  1296.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1297.  
  1298.     if (draw_contour & CONTOUR_BASE) {
  1299.     for (i = 0; i < cntr->num_pts; i++) {
  1300.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1301.                  &x, &y);
  1302.  
  1303.              if (i > 0) {
  1304.                  clip_vector(x,y);
  1305.                  if(i == 1) suppressMove = TRUE;
  1306.              } else {
  1307.                  clip_move(x,y);
  1308.              }
  1309.          }
  1310.      }
  1311.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1312. }
  1313.  
  1314. /* cntr3d_points:
  1315.  * Plot a surface contour in POINTSTYLE style
  1316.  */
  1317. static void cntr3d_points(cntr, plot)
  1318.     struct gnuplot_contours *cntr;
  1319.     struct surface_points *plot;
  1320. {
  1321.     int i;
  1322.     unsigned int x,y;
  1323.     struct termentry *t = term;
  1324.  
  1325.     if (draw_contour & CONTOUR_SRF) {
  1326.     for (i = 0; i < cntr->num_pts; i++) {
  1327.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1328.                  &x, &y);
  1329.  
  1330.         if (!clip_point(x,y))
  1331.         (*t->point)(x,y, plot->point_type);
  1332.         }
  1333.     }
  1334.  
  1335.     if (draw_contour & CONTOUR_BASE) {
  1336.     for (i = 0; i < cntr->num_pts; i++) {
  1337.            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1338.                  &x, &y);
  1339.  
  1340.         if (!clip_point(x,y))
  1341.         (*t->point)(x,y, plot->point_type);
  1342.         }
  1343.     }
  1344. }
  1345.  
  1346. /* cntr3d_dots:
  1347.  * Plot a surface contour in DOTS style
  1348.  */
  1349. static void cntr3d_dots(cntr)
  1350.     struct gnuplot_contours *cntr;
  1351. {
  1352.     int i;
  1353.     unsigned int x,y;
  1354.     struct termentry *t = term;
  1355.  
  1356.     if (draw_contour & CONTOUR_SRF) {
  1357.     for (i = 0; i < cntr->num_pts; i++) {
  1358.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1359.                  &x, &y);
  1360.  
  1361.         if (!clip_point(x,y))
  1362.         (*t->point)(x,y, -1);
  1363.         }
  1364.     }
  1365.  
  1366.     if (draw_contour & CONTOUR_BASE) {
  1367.     for (i = 0; i < cntr->num_pts; i++) {
  1368.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1369.                  &x, &y);
  1370.  
  1371.         if (!clip_point(x,y))
  1372.         (*t->point)(x,y, -1);
  1373.         }
  1374.     }
  1375. }
  1376.  
  1377.  
  1378.  
  1379. /* map xmin | xmax to 0 | 1 and same for y
  1380.  * 0.1 avoids any rounding errors
  1381.  */
  1382. #define MAP_HEIGHT_X(x) ( (int) (((x)-x_min3d)/(x_max3d-x_min3d)+0.1) )
  1383. #define MAP_HEIGHT_Y(y) ( (int) (((y)-y_min3d)/(y_max3d-y_min3d)+0.1) )
  1384.  
  1385. /* if point is at corner, update height[][] and depth[][]
  1386.  * we are still assuming that extremes of surfaces are at corners,
  1387.  * but we are not assuming order of corners
  1388.  */
  1389. static void check_corner_height(p,height,depth)
  1390. struct coordinate GPHUGE *p;
  1391. double height[2][2];
  1392. double depth[2][2];
  1393. {
  1394.     if (p->type != INRANGE) return;
  1395.     if ( (fabs(p->x - x_min3d)<zero || fabs(p->x - x_max3d)<zero) &&
  1396.          (fabs(p->y - y_min3d)<zero || fabs(p->y - y_max3d)<zero)) {
  1397.         unsigned int x= MAP_HEIGHT_X(p->x);
  1398.         unsigned int y= MAP_HEIGHT_Y(p->y);
  1399.         if (height[x][y] < p->z)
  1400.             height[x][y] = p->z;
  1401.         if (depth[x][y] > p->z)
  1402.             depth[x][y] = p->z;
  1403.     }
  1404. }        
  1405.         
  1406.  
  1407. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  1408. static void draw_bottom_grid(plot, plot_num)
  1409.     struct surface_points *plot;
  1410.     int plot_num;
  1411. {
  1412.     unsigned int x,y;    /* point in terminal coordinates */
  1413.     struct termentry *t = term;
  1414.     char ss[MAX_LINE_LEN+1];
  1415.  
  1416.     /* work out where the axes and tics are drawn */
  1417.  
  1418.     {
  1419.         int quadrant=surface_rot_z/90;
  1420.         if ( (quadrant+1)&2) {
  1421.             zaxis_x = x_max3d;
  1422.             xaxis_y = y_max3d;
  1423.         } else {
  1424.             zaxis_x = x_min3d;
  1425.             xaxis_y = y_min3d;
  1426.         }
  1427.  
  1428.         if (quadrant&2) {
  1429.             zaxis_y = y_max3d;
  1430.             yaxis_x = x_min3d;
  1431.         } else {
  1432.             zaxis_y = y_min3d;
  1433.             yaxis_x = x_max3d;
  1434.         }
  1435.  
  1436.         if (surface_rot_x > 90) {
  1437.             /* labels on the back axes */
  1438.             back_x = yaxis_x = x_min3d + x_max3d - yaxis_x;
  1439.             back_y = xaxis_y = y_min3d + y_max3d - xaxis_y;
  1440.         } else {
  1441.             back_x = x_min3d + x_max3d - yaxis_x;
  1442.             back_y = y_min3d + y_max3d - xaxis_y;
  1443.         }
  1444.     }
  1445.  
  1446.     if (draw_border) {
  1447.     unsigned int bl_x, bl_y; /* bottom left */
  1448.     unsigned int bb_x, bb_y; /* bottom back */
  1449.     unsigned int br_x, br_y; /* bottom right */
  1450.     unsigned int bf_x, bf_y; /* bottom front */
  1451. #ifndef LITE
  1452.     int save_update=hidden_no_update;
  1453.     hidden_no_update=TRUE;
  1454. #endif /* LITE */
  1455.     setlinestyle(-2);
  1456.  
  1457.     map3d_xy(zaxis_x, zaxis_y, base_z, &bl_x, &bl_y);
  1458.     map3d_xy( back_x,  back_y, base_z, &bb_x, &bb_y);
  1459.     map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, base_z, &br_x, &br_y);
  1460.     map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, base_z, &bf_x, &bf_y);
  1461.  
  1462.     /* border around base */
  1463.     {
  1464.         int save=hidden_active;
  1465.         hidden_active=FALSE; /* this is in front */
  1466.         if (draw_border&4) draw_clip_line(br_x, br_y, bf_x, bf_y);
  1467.         if (draw_border&1) draw_clip_line(bl_x, bl_y, bf_x, bf_y);
  1468.         hidden_active=save;
  1469.     }
  1470.     if (draw_border&2) draw_clip_line(bl_x, bl_y, bb_x, bb_y);
  1471.     if (draw_border&8) draw_clip_line(br_x, br_y, bb_x, bb_y);
  1472.  
  1473.     if ( draw_surface || (draw_contour&CONTOUR_SRF)) {
  1474.         int save=hidden_active;
  1475.         /* map the 8 corners to screen */
  1476.         unsigned int fl_x, fl_y; /* floor left */
  1477.         unsigned int fb_x, fb_y; /* floor back */
  1478.         unsigned int fr_x, fr_y; /* floor right */
  1479.         unsigned int ff_x, ff_y; /* floor front */
  1480.  
  1481.         unsigned int tl_x, tl_y; /* top left */
  1482.         unsigned int tb_x, tb_y; /* top back */
  1483.         unsigned int tr_x, tr_y; /* top right */
  1484.         unsigned int tf_x, tf_y; /* top front */
  1485.  
  1486.         map3d_xy(zaxis_x, zaxis_y, floor_z, &fl_x, &fl_y);
  1487.         map3d_xy( back_x,  back_y, floor_z, &fb_x, &fb_y);
  1488.         map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, floor_z, &fr_x, &fr_y);
  1489.         map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, floor_z, &ff_x, &ff_y);
  1490.  
  1491.         map3d_xy(zaxis_x, zaxis_y, ceiling_z, &tl_x, &tl_y);
  1492.         map3d_xy( back_x,  back_y, ceiling_z, &tb_x, &tb_y);
  1493.         map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, ceiling_z, &tr_x, &tr_y);
  1494.         map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, ceiling_z, &tf_x, &tf_y);
  1495.  
  1496.         /* vertical lines, to surface or to very top */
  1497.         if ( (draw_border & 0xf0)==0xf0) {
  1498.             /* all four verticals drawn - save some time */
  1499.             draw_clip_line(fl_x, fl_y, tl_x, tl_y);
  1500.             draw_clip_line(fb_x, fb_y, tb_x, tb_y);
  1501.             draw_clip_line(fr_x, fr_y, tr_x, tr_y);
  1502.             hidden_active=FALSE; /* this is in front */
  1503.             draw_clip_line(ff_x, ff_y, tf_x, tf_y);
  1504.             hidden_active=save;
  1505.         } else {
  1506.             /* search surfaces for heights at corners */
  1507.             double height[2][2];
  1508.             double depth[2][2];
  1509.             unsigned int zaxis_i=MAP_HEIGHT_X(zaxis_x);
  1510.             unsigned int zaxis_j=MAP_HEIGHT_Y(zaxis_y);
  1511.             unsigned int back_i=MAP_HEIGHT_X(back_x);
  1512.             int back_j=MAP_HEIGHT_Y(back_y);
  1513.  
  1514.             height[0][0]=height[0][1]=height[1][0]=height[1][1]=base_z;
  1515.             depth[0][0]=depth[0][1]=depth[1][0]=depth[1][1]=base_z;
  1516.         
  1517.             for (; --plot_num >= 0; plot=plot->next_sp) {
  1518.             struct iso_curve *curve=plot->iso_crvs;
  1519.             int count=curve->p_count;
  1520.             int iso;
  1521.             if (plot->plot_type==DATA3D) {
  1522.                 if (!plot->has_grid_topology) continue;
  1523.                 iso=plot->num_iso_read;
  1524.             } else
  1525.                 iso=iso_samples_2;
  1526.             
  1527.             check_corner_height(curve->points, height, depth);
  1528.             check_corner_height(curve->points+count-1, height, depth);
  1529.             while (--iso)
  1530.                 curve=curve->next;
  1531.             check_corner_height(curve->points, height, depth);
  1532.             check_corner_height(curve->points+count-1, height, depth);
  1533.             }
  1534.  
  1535. #define VERTICAL(mask, x,y,i,j,bx,by,tx,ty) \
  1536.  if (draw_border&mask) \
  1537.   draw_clip_line(bx,by,tx,ty);\
  1538. else if (height[i][j]!=depth[i][j]) \
  1539. { unsigned int a0,b0, a1, b1; \
  1540.   map3d_xy(x,y,depth[i][j],&a0,&b0); \
  1541.   map3d_xy(x,y,height[i][j],&a1,&b1); \
  1542.   draw_clip_line(a0,b0,a1,b1); \
  1543. }
  1544.  
  1545.             VERTICAL(16, zaxis_x, zaxis_y, zaxis_i, zaxis_j,fl_x, fl_y, tl_x, tl_y)
  1546.             VERTICAL(32, back_x, back_y, back_i, back_j,fb_x, fb_y, tb_x, tb_y)
  1547.             VERTICAL(64, x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, 1-zaxis_i, 1-zaxis_j,fr_x, fr_y, tr_x, tr_y)
  1548.             hidden_active=FALSE;
  1549.             VERTICAL(128, x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, 1-back_i, 1-back_j,ff_x, ff_y, tf_x, tf_y)
  1550.             hidden_active=save;
  1551.         }
  1552.  
  1553.         /* now border lines on top */
  1554.         if (draw_border&256) draw_clip_line(tl_x, tl_y, tb_x, tb_y);
  1555.         if (draw_border&512) draw_clip_line(tr_x, tr_y, tb_x, tb_y);
  1556.         /* these lines are in front of surface (?) */
  1557.         hidden_active=FALSE;
  1558.         if (draw_border&1024) draw_clip_line(tl_x, tl_y, tf_x, tf_y);
  1559.         if (draw_border&2048) draw_clip_line(tr_x, tr_y, tf_x, tf_y);
  1560.         hidden_active=save;
  1561.     }
  1562. #ifndef LITE
  1563.     hidden_no_update=save_update;
  1564. #endif /* LITE */
  1565.     }
  1566.  
  1567.     if (xtics || *xlabel.text) {
  1568.         unsigned int x0,y0,x1,y1;
  1569.         double mid_x = (x_max3d+x_min3d)/2;
  1570.         double len;
  1571.         map3d_xy(mid_x, xaxis_y, base_z, &x0, &y0);
  1572.         map3d_xy(mid_x, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
  1573.         {    /* take care over unsigned quantities */
  1574.             int dx = x1-x0;
  1575.             int dy = y1-y0;
  1576.             len=sqrt((double)(dx*dx+dy*dy));
  1577.             tic_unitx = dx/len;
  1578.             tic_unity = dy/len;
  1579.         }
  1580.  
  1581.         if (xtics) {
  1582.             gen_tics(FIRST_X_AXIS, &xticdef,grid&(GRID_X|GRID_MX),mxtics,mxtfreq, xtick_callback);
  1583.         }
  1584.  
  1585.         if (*xlabel.text) {
  1586.             /* label at xaxis_y + 1/4 of (xaxis_y-other_y) */
  1587.             double step = (2*xaxis_y-y_max3d-y_min3d)/4;
  1588.                 map3d_xy(mid_x, xaxis_y+step, base_z,&x1,&y1);
  1589.             x1 += xlabel.xoffset * t->h_char;
  1590.             y1 += xlabel.yoffset * t->v_char;
  1591.             if (!tic_in) {
  1592.                 x1 -= tic_unitx*ticscale*(t->h_tic);
  1593.                 y1 -= tic_unity*ticscale*(t->v_tic);
  1594.             }
  1595.             strcpy(ss, xlabel.text); /* write_multiline mods it */
  1596.             write_multiline(x1,y1,ss, CENTRE, JUST_TOP,0, xlabel.font);
  1597.         }
  1598.     }
  1599.  
  1600.     if (ytics || *ylabel.text) {
  1601.         unsigned int x0,y0,x1,y1;
  1602.         double mid_y = (y_max3d+y_min3d)/2;
  1603.         double len;
  1604.         map3d_xy(yaxis_x, mid_y, base_z, &x0, &y0);
  1605.         map3d_xy(x_min3d + x_max3d - yaxis_x,  mid_y, base_z, &x1, &y1);
  1606.         {    /* take care over unsigned quantities */
  1607.             int dx = x1-x0;
  1608.             int dy = y1-y0;
  1609.             len=sqrt((double)(dx*dx+dy*dy));
  1610.             tic_unitx = dx/len;
  1611.             tic_unity = dy/len;
  1612.         }
  1613.         if (ytics) {
  1614.             gen_tics(FIRST_Y_AXIS, &yticdef,grid&(GRID_Y|GRID_MY),mytics,mytfreq, ytick_callback);
  1615.         }
  1616.  
  1617.         if (*ylabel.text) {
  1618.             double step = (x_max3d+x_min3d-2*yaxis_x)/4;
  1619.                 map3d_xy(yaxis_x-step, mid_y, base_z,&x1,&y1);
  1620.             x1 += ylabel.xoffset * t->h_char;
  1621.             y1 += ylabel.yoffset * t->v_char;
  1622.             if (!tic_in) {
  1623.                 x1 -= tic_unitx*ticscale*(t->h_tic);
  1624.                 y1 -= tic_unity*ticscale*(t->v_tic);
  1625.             }
  1626.             strcpy(ss, ylabel.text); /* write_multiline mods it */
  1627.             write_multiline(x1,y1,ss, CENTRE, JUST_TOP,0, ylabel.font);
  1628.         }
  1629.     }
  1630.     
  1631.     /* do z tics */
  1632.  
  1633.     if (ztics && (draw_surface || (draw_contour&CONTOUR_SRF))) {
  1634.         gen_tics(FIRST_Z_AXIS, &zticdef, grid&(GRID_Z|GRID_MZ), mztics, mztfreq, ztick_callback);
  1635.     }
  1636.  
  1637.     if ( (xzeroaxis>=-2) && !is_log_y && inrange(0,y_min3d, y_max3d)) {
  1638.         unsigned int x,y,x1,y1;
  1639.         (*t->linetype)(xzeroaxis);
  1640.         map3d_xy(x_min3d, 0.0, base_z, &x, &y);
  1641.         map3d_xy(x_max3d, 0.0, base_z, &x1, &y1);
  1642.         draw_clip_line(x,y,x1,y1);
  1643.     }
  1644.     if ((yzeroaxis>=-2) && !is_log_x && inrange(0,x_min3d, x_max3d)) {
  1645.         unsigned int x,y,x1,y1;
  1646.         (*t->linetype)(yzeroaxis);
  1647.         map3d_xy(0.0, y_min3d, base_z, &x, &y);
  1648.         map3d_xy(0.0, y_max3d, base_z, &x1, &y1);
  1649.         draw_clip_line(x,y,x1,y1);
  1650.     }
  1651.  
  1652. /* PLACE ZLABEL - along the middle grid Z axis - eh ? */
  1653.     if (*zlabel.text && (draw_surface || (draw_contour & CONTOUR_SRF))) {
  1654.            map3d_xy(zaxis_x,zaxis_y,z_max3d + (z_max3d-base_z)/4, &x, &y);
  1655.  
  1656.        x += zlabel.xoffset * t->h_char;
  1657.        y += zlabel.yoffset * t->v_char;
  1658.  
  1659.        strcpy(ss, zlabel.text);
  1660.        write_multiline(x,y,ss,CENTRE, CENTRE, 0, zlabel.font);
  1661.        
  1662.     }
  1663. }
  1664.  
  1665.  
  1666. static void xtick_callback(axis,place,text,grid)
  1667. int axis;
  1668. double place;
  1669. char *text;
  1670. int grid; /* linetype or -2 for none */
  1671. {
  1672.     unsigned int x,y,x1,y1;
  1673.     double scale=(text?ticscale:miniticscale);
  1674.     int dirn=tic_in?1:-1;
  1675.     register struct termentry *t = term;
  1676.     map3d_xy(place, xaxis_y, base_z, &x, &y);
  1677.     if (grid > -2) {
  1678.         (*t->linetype)(grid);
  1679.         /* to save mapping twice, map non-axis y */
  1680.         map3d_xy(place, y_min3d+y_max3d-xaxis_y, base_z, &x1, &y1);
  1681.         draw_clip_line(x,y,x1,y1);
  1682.         (*t->linetype)(-2);
  1683.     }
  1684.     if (xtics&TICS_ON_AXIS) {
  1685.         map3d_xy(place, (y_min3d+y_max3d)/2, base_z, &x, &y);
  1686.     }
  1687.     x1=x+tic_unitx*scale*(t->h_tic)*dirn;
  1688.     y1=y+tic_unity*scale*(t->v_tic)*dirn;
  1689.     draw_clip_line(x,y,x1,y1);
  1690.     if (text) {
  1691.         int just;
  1692.         if (tic_unitx < -0.9)
  1693.             just=LEFT;
  1694.         else if (tic_unitx < 0.9)
  1695.             just=CENTRE;
  1696.         else
  1697.             just=RIGHT;
  1698.         x1=x-tic_unitx*(t->h_tic)*2;
  1699.         y1=y-tic_unity*(t->v_tic)*2;
  1700.         if (!tic_in) {
  1701.             x1 -= tic_unitx*(t->h_tic)*ticscale;
  1702.             y1 -= tic_unity*(t->v_tic)*ticscale;
  1703.         }
  1704.         clip_put_text_just(x1,y1,text,just);
  1705.     }
  1706.     if (xtics & TICS_MIRROR) {
  1707.         map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x, &y);
  1708.         x1=x-tic_unitx*scale*(t->h_tic)*dirn;
  1709.         y1=y-tic_unity*scale*(t->v_tic)*dirn;
  1710.         draw_clip_line(x,y,x1,y1);
  1711.     }
  1712. }
  1713.  
  1714. static void ytick_callback(axis,place,text,grid)
  1715. int axis;
  1716. double place;
  1717. char *text;
  1718. int grid;
  1719. {
  1720.     unsigned int x,y,x1,y1;
  1721.     double scale=(text?ticscale:miniticscale);
  1722.     int dirn=tic_in?1:-1;
  1723.     register struct termentry *t = term;
  1724.     map3d_xy(yaxis_x, place, base_z, &x, &y);
  1725.     if (grid > -2) {
  1726.         (*t->linetype)(grid);
  1727.         map3d_xy(x_min3d+x_max3d-yaxis_x, place, base_z, &x1, &y1);
  1728.         draw_clip_line(x,y,x1,y1);
  1729.         (*t->linetype)(-2);
  1730.     }
  1731.     if (ytics&TICS_ON_AXIS) {
  1732.         map3d_xy( (x_min3d+x_max3d)/2, place, base_z, &x, &y);
  1733.     }
  1734.     x1=x+tic_unitx*scale*dirn*(t->h_tic);
  1735.     y1=y+tic_unity*scale*dirn*(t->v_tic);
  1736.     draw_clip_line(x,y,x1,y1);
  1737.     if (text) {
  1738.         int just;
  1739.         if (tic_unitx < -0.9)
  1740.             just=LEFT;
  1741.         else if (tic_unitx < 0.9)
  1742.             just=CENTRE;
  1743.         else
  1744.             just=RIGHT;
  1745.         x1=x-tic_unitx*(t->h_tic)*2;
  1746.         y1=y-tic_unity*(t->v_tic)*2;
  1747.         if (!tic_in) {
  1748.             x1 -= tic_unitx*(t->h_tic)*ticscale;
  1749.             y1 -= tic_unity*(t->v_tic)*ticscale;
  1750.         }
  1751.         clip_put_text_just(x1,y1,text,just);
  1752.     }
  1753.     if (ytics & TICS_MIRROR) {
  1754.         map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x, &y);
  1755.         x1=x-tic_unitx*scale*(t->h_tic)*dirn;
  1756.         y1=y-tic_unity*scale*(t->v_tic)*dirn;
  1757.         draw_clip_line(x,y,x1,y1);
  1758.     }
  1759. }
  1760.  
  1761. static void ztick_callback(axis,place,text,grid)
  1762. int axis;
  1763. double place;
  1764. char *text;
  1765. int grid;
  1766. {
  1767.     int len=(text?ticscale:miniticscale)*(tic_in?1:-1)*term->h_tic;
  1768.     unsigned int x,y;
  1769.     register struct termentry *t = term;
  1770.     if (grid > -2) {
  1771.         unsigned int x1,y1,x2,y2,x3,y3;
  1772.         double other_x=x_min3d+x_max3d-zaxis_x;
  1773.         double other_y=y_min3d+y_max3d-zaxis_y;
  1774.         (*t->linetype)(grid);
  1775.         map3d_xy(zaxis_x, zaxis_y, place, &x1, &y1);
  1776.         map3d_xy(back_x, back_y, place, &x2, &y2);
  1777.         map3d_xy(other_x, other_y, place, &x3, &y3);
  1778.         draw_clip_line(x1,y1,x2,y2);
  1779.         draw_clip_line(x2,y2,x3,y3);
  1780.         (*t->linetype)(-2);
  1781.     }
  1782.     map3d_xy(zaxis_x, zaxis_y, place, &x, &y);
  1783.     draw_clip_line(x,y,x+len, y);
  1784.     if (text) {
  1785.         int x1=x-term->h_tic*2;
  1786.         if (!tic_in)
  1787.             x1 -= term->h_tic*ticscale;
  1788.         clip_put_text_just(x1,y,text,RIGHT);
  1789.     }
  1790.     if (ztics & TICS_MIRROR) {
  1791.         double other_x = x_min3d + x_max3d - zaxis_x;
  1792.         double other_y = y_min3d + y_max3d - zaxis_y;
  1793.         map3d_xy(other_x, other_y, place, &x, &y);
  1794.         draw_clip_line(x,y,x-len, y);
  1795.     }        
  1796. }
  1797.  
  1798.  
  1799. static void map_position(pos, x, y, what)
  1800. struct position *pos;
  1801. unsigned int *x, *y;
  1802. char *what;
  1803. {
  1804.  
  1805.     double xpos=pos->x;
  1806.     double ypos=pos->y;
  1807.     double zpos=pos->z;
  1808.     int screens=0; /* need either 0 or 3 screen co-ordinates */
  1809.  
  1810.     switch(pos->scalex) {
  1811.         case first_axes:
  1812.         case second_axes:
  1813.             xpos = LogScale(xpos, is_log_x, log_base_log_x, what, "x");
  1814.             break;
  1815.         case graph:
  1816.             xpos=min_array[FIRST_X_AXIS]+xpos*(max_array[FIRST_X_AXIS]-min_array[FIRST_X_AXIS]);
  1817.             break;
  1818.         case screen:
  1819.             ++screens;
  1820.     }
  1821.  
  1822.     switch(pos->scaley) {
  1823.         case first_axes:
  1824.         case second_axes:
  1825.             ypos = LogScale(ypos, is_log_y, log_base_log_y, what, "y");
  1826.             break;
  1827.         case graph:
  1828.             ypos=min_array[FIRST_Y_AXIS]+ypos*(max_array[FIRST_Y_AXIS]-min_array[FIRST_Y_AXIS]);
  1829.             break;
  1830.         case screen:
  1831.             ++screens;
  1832.     }
  1833.  
  1834.     switch(pos->scalez) {
  1835.         case first_axes:
  1836.         case second_axes:
  1837.             zpos = LogScale(zpos, is_log_z, log_base_log_z, what, "z");
  1838.             break;
  1839.         case graph:
  1840.             zpos=min_array[FIRST_Z_AXIS]+zpos*(max_array[FIRST_Z_AXIS]-min_array[FIRST_Z_AXIS]);
  1841.             break;
  1842.         case screen:
  1843.             ++screens;
  1844.     }
  1845.  
  1846.     if (screens==0) {
  1847.             map3d_xy(xpos,ypos,zpos, x,y);
  1848.             return;
  1849.     }
  1850.  
  1851.     if (screens != 3) {
  1852.         graph_error("Cannot mix screen co-ordinates with other types");
  1853.     }
  1854.  
  1855.     {
  1856.         register struct termentry *t = term;
  1857.         *x = pos->x*(t->xmax) + 0.5;
  1858.         *y = pos->y*(t->ymax) + 0.5;
  1859.     }
  1860.  
  1861.     return;                
  1862. }
  1863.  
  1864.  
  1865.  
  1866. static void key_text(xl, yl, text)
  1867. int xl, yl;
  1868. char *text;
  1869. {
  1870.     if ( key_just == JLEFT && key == -1 ) {
  1871.         (*term->justify_text)(LEFT); 
  1872.         (*term->put_text)(xl+key_text_left, yl,text);
  1873.     } else {
  1874.         if ((*term->justify_text)(RIGHT)) {
  1875.             if ( key == 1 )
  1876.                 clip_put_text(xl+key_text_right,yl,text);
  1877.             else
  1878.                 (*term->put_text)(xl+key_text_right,yl,text);
  1879.         } else {
  1880.             int x=xl+key_text_right-(term->h_char)*strlen(text);
  1881.             if (key == 1) {
  1882.                   if (i_inrange(x, xleft, xright))
  1883.                     clip_put_text(x,yl,text);
  1884.             } else {
  1885.                 (*term->put_text)(x,yl,text);
  1886.             }
  1887.         }
  1888.     }
  1889. }
  1890.  
  1891. static void key_sample_line(xl, yl)
  1892. int xl, yl;
  1893. {
  1894.     if (key == -1) {
  1895.         (*term->move)(xl+key_sample_left,yl);
  1896.         (*term->vector)(xl+key_sample_right,yl);
  1897.     } else {
  1898.         clip_move(xl+key_sample_left,yl);
  1899.         clip_vector(xl+key_sample_right,yl);
  1900.     }
  1901. }
  1902.  
  1903. static void key_sample_point(xl, yl, pointtype)
  1904. int xl, yl;
  1905. int pointtype;
  1906. {
  1907.     if (!clip_point(xl+key_point_offset,yl)) {
  1908.         (*term->point)(xl+key_point_offset,yl, pointtype);
  1909.     } else {
  1910.         (*term->point)(xl+key_point_offset,yl, pointtype);
  1911.     }
  1912. }
  1913.  
  1914.